/**
 * project7
 *
 * brief description of the program
 *
 * This program is released to public domain according to
 * author's wish, you can view full license at
 * http://tomatoeskit.org/upload/PublicDomainLicense.txt
 *
 * @author Fangning CHENG (Alpha.L Cheng) <chengf@purdue.edu>
 *
 * @lab section number 
 *
 * @date Nov 8, 2013
 *
 */
import java.util.TreeMap;
import edu.purdue.cs.cs180.channel.*;

abstract public class Server implements MessageListener {
    Channel channel;
    TreeMap<String, TreeMap<String, Integer>> timeTable = new TreeMap<String, TreeMap<String, Integer>>();

    protected class EndPointInfo {
        public final String building;
        public final String urgency;
        public final int    clientID;

        EndPointInfo(String building, int clientID) {
            this.building = building;
            this.clientID = clientID;
            this.urgency = null;
        }
        
        EndPointInfo(String building, int clientID, String urgency) {
            this.building = building;
            this.clientID = clientID;
            this.urgency = urgency;
        }
    }
    
    Server (Channel cnl)
    {
        channel = cnl;
        initialize();
        channel.setMessageListener(this);
        System.err.println("\tProject 7 Server started");
    }

    protected void initialize()
    {
        TreeMap<String, Integer> cl50 = new TreeMap<String, Integer>();
        cl50.put("CL50",    0);
        cl50.put("EE",      8);
        cl50.put("LWSN",    6);
        cl50.put("PMU",     5);
        cl50.put("PUSH",    4);
        timeTable.put("CL50", cl50);
        
        TreeMap<String, Integer> ee = new TreeMap<String, Integer>();
        ee.put("CL50",    8);
        ee.put("EE",      0);
        ee.put("LWSN",    4);
        ee.put("PMU",     2);
        ee.put("PUSH",    5);
        timeTable.put("EE", ee);
        
        TreeMap<String, Integer> lwsn = new TreeMap<String, Integer>();
        lwsn.put("CL50",    6);
        lwsn.put("EE",      4);
        lwsn.put("LWSN",    0);
        lwsn.put("PMU",     3);
        lwsn.put("PUSH",    1);
        timeTable.put("LWSN", lwsn);
        
        TreeMap<String, Integer> pmu = new TreeMap<String, Integer>();
        pmu.put("CL50",    5);
        pmu.put("EE",      2);
        pmu.put("LWSN",    3);
        pmu.put("PMU",     0);
        pmu.put("PUSH",    7);
        timeTable.put("PMU", pmu);
        
        TreeMap<String, Integer> push = new TreeMap<String, Integer>();
        push.put("CL50",    4);
        push.put("EE",      5);
        push.put("LWSN",    1);
        push.put("PMU",     7);
        push.put("PUSH",    0);
        timeTable.put("PUSH", push);
        
    }

    @Override
    abstract public void messageReceived(String message, int clientID);

    /**
     * 
     * @param volunteerID
     * @param requesterID
     * @param volunteerTime
     * @param requesterBuilding
     * @param requesterUrgency
     * @param volunteerBuilding
     * @return
     */
    protected boolean sendMessages(int volunteerID, int requesterID, int volunteerTime, 
            String requesterBuilding, String requesterUrgency, String volunteerBuilding)
    {
        try {
            // Send message to requester
            channel.sendMessage(
                    String.format("VOLUNTEER %d %d", volunteerID, volunteerTime),
                    requesterID);
            // [VOLUNTEER ID TIME]

            // Send message to volunteer
            channel.sendMessage(
                    String.format("LOCATION %s %s", requesterBuilding, requesterUrgency),
                    volunteerID);
            // [LOCATION BLDG URGENCY]
            
            System.err.println(String.format("\t\tMessage sent to %d: VOLUNTEER %d %d", 
                    requesterID, volunteerID, volunteerTime));
            System.err.println(String.format("\t\tMessage sent to %d: LOCATION %s %s", 
                    volunteerID, requesterBuilding, requesterUrgency));
            System.err.println(
                    String.format("\t\tRequester %d at %s is taken care by Volunteer %d from %s",
                            requesterID, requesterBuilding, volunteerID, volunteerBuilding));
        } catch (ChannelException e) {
            System.err.println("\t\tFailed to send message: " + e.getMessage());
            return false;
        }
        return true;
    }
    
    
    /**
     * 
     * @param volunteerID
     * @param requesterID
     * @param volunteerTime
     * @param requesterBuilding
     * @param requesterUrgency
     * @return
     */
    protected boolean sendMessages(int volunteerID, int requesterID, int volunteerTime, 
            String requesterBuilding, String requesterUrgency)
    {
        return sendMessages(volunteerID, requesterID, volunteerTime, 
                requesterBuilding, requesterUrgency, "Unknown");
    }
      

      
    @SuppressWarnings("unused")
    public static void main(String[] args)
    {
        int port;

        if (args.length > 1) {
            if (args[0].equals("help")) {
                System.err.println("Usage: java Server port algorithm");
                System.err.println("Run project 7 server");
                System.err.println("\tport must be in the range from 1024 to 65535");
                System.err.println("\talgorithm can be `FCFS', `CLOSEST' or `URGENCY'");
                return;
            } else {
                try {
                    port = Integer.parseInt(args[0]);
                } catch (Exception ex) {
                    System.err.println("Invalid port");
                    return;
                }
                if (port < 1024 || port > 65535) {
                    System.err.println("Invalid port");
                    return;
                }
            }
            
            try {
                if (args[1].equals("FCFS")) {
                    Server srv = new FCFSServer(new TCPChannel(port)); 
                    return;
                }
                
                if (args[1].equals("CLOSEST")) {
                    Server srv = new LocBasedServer(new TCPChannel(port));
                    return;
                }
                
                if (args[1].equals("URGENCY")) {
                    Server srv = new UrgencyServer(new TCPChannel(port));
                    return;
                }    
                
                System.err.println("Server: Unrecognized algorithm");
            } catch (Exception ex) {
                System.err.println(ex.getMessage());
            }
            
        } else {
            System.err.println("Server: missing file operand");
            System.err.println("Try `java Server help' for more information.");
            return;
        }
    }
}


